package com.mathdroid.crawler.armor;
import java.net.*;
import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.mathdroid.crawler.shared.EItemType;


public final class Crawler {
	
	private String urlPart0 = "http://www.torhead.com/items/catg/";
	private String urlPart1 = "/subcatg/"; 
	private String urlPart2 = "/reqlevel/50-50/page/"; 
	
	private HashMap<EItemType, Integer> catgMapping = 
		new HashMap<EItemType, Integer>();
	
	private HashMap<EArmorProficiency, Integer> armorSubcatgMapping = 
		new HashMap<EArmorProficiency, Integer>();
	
	private HashMap<EItemSlot, Integer> armorSlotMapping = 
		new HashMap<EItemSlot, Integer>();
	
	//<span><b>1</b> - <b>50</b> of <b>186</b></span>
	private static final String PAGES_PATTERN = "</b> of <b>\\d+</b></span>";
	
	//<a href="/item/KHYwNu"></a>
	private static final String ITEM_PATTERN = "<a href=\"/item/\\w+\"></a>";
	
	//<td class="nobr">56</td><td class="nobr">50</td>
	private static final String ILVL_PATTERN = "<td class=\"nobr\">\\d+</td><td class=\"nobr\">\\d+</td>";
	
	private BufferedWriter out = null;
	
	private LinkedList<String> filesXML = new LinkedList<String>();
	
	public Crawler() {
		this.initMappings();
		this.buildWeapons();
	}

	private void initMappings() {
		this.armorSubcatgMapping.put(EArmorProficiency.LIGHT, 1);
		this.armorSubcatgMapping.put(EArmorProficiency.MEDIUM, 2);
		this.armorSubcatgMapping.put(EArmorProficiency.HEAVY, 3);
		this.armorSubcatgMapping.put(EArmorProficiency.ACCESSOIRS, 4);
		//this.armorSubcatgMapping.put(EArmorProficiency.MISCELLANEOUS, 0);

		
		this.catgMapping.put(EItemType.WEAPON, 1);
		this.catgMapping.put(EItemType.ARMOR, 2);
		this.catgMapping.put(EItemType.MODULE, 3);		
		
//		this.armorSlotMapping.put(EItemSlot.WRISTS, 5);
//		this.armorSlotMapping.put(EItemSlot.WAIST, 6);
//		this.armorSlotMapping.put(EItemSlot.CHEST, 7);
//		this.armorSlotMapping.put(EItemSlot.EAR, 8);
		this.armorSlotMapping.put(EItemSlot.HEAD, 9);
//		this.armorSlotMapping.put(EItemSlot.FEET, 10);
//		this.armorSlotMapping.put(EItemSlot.HANDS, 11);
//		this.armorSlotMapping.put(EItemSlot.IMPLANT, 12);
//		this.armorSlotMapping.put(EItemSlot.LEGS, 13);
//		this.armorSlotMapping.put(EItemSlot.RELIC, 49);
	}

	private void buildWeapons() {
		int catg = this.catgMapping.get(EItemType.ARMOR);
		int subcatg = 0;
		int items = 0;
		int pages = 0;
		
		/* Go through all weapon subcategories an get how many pages each has */
		for (EItemSlot slot : this.armorSlotMapping.keySet()) {
			for (EArmorProficiency p : this.armorSubcatgMapping.keySet()) {
				subcatg = this.armorSubcatgMapping.get(p);
				
				items = this.getItemsOfCategory(
						urlPart0 + catg + urlPart1 + subcatg + "/slot/" 
						+ this.armorSlotMapping.get(slot) + urlPart2 + 1);
				pages = (int) Math.ceil(items / 50d);
//				System.out.println(urlPart0 + catg + urlPart1 + subcatg + "/slot/" + this.armorSlotMapping.get(slot) + urlPart2 + 1);
//				System.out.println(slot.toString().toLowerCase().replaceAll("\\s", "")
//						+ "_" + p.toString().toLowerCase().replaceAll("\\s", "") 
//						+ " has " + items + " items on " + pages + " pages.");
				
				if (items > 0) {
					FileWriter fstream = null;
					try {
						fstream = new FileWriter(slot.toString().toLowerCase().replaceAll("\\s", "")
								+ "_" + p.toString().toLowerCase().replaceAll("\\s", "") + ".xml");
						
						this.filesXML.add("\t\t<file>vanilla/" + slot.toString().toLowerCase().replaceAll("\\s", "")
						+ "_" + p.toString().toLowerCase().replaceAll("\\s", "") + "</file>");
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					this.out = new BufferedWriter(fstream);
					try {
						this.out.write("<?xml version=\"1.0\" ?>\n" +
								"<!DOCTYPE items SYSTEM \"..\\dtd\\items.dtd\">\n\n");
						this.out.write("\n<items>\n");
						this.out.write("<type>" + "Armor" + "</type>\n");
						this.out.write("<proficiency>" + p.toString() + "</proficiency>\n\n");
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					this.parseArmorCategory(p, pages, slot);
					
					try {
//						System.out.println("Finished " + slot.toString().toLowerCase().replaceAll("\\s", "")
//								+ "_" + p.toString().toLowerCase().replaceAll("\\s", ""));
						this.out.write("\n</items>\n");
						this.out.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}				
			}
		}
		
		for (String s : this.filesXML) {
			System.out.println(s);
		}
		
	}
	
	private void parseArmorCategory(EArmorProficiency p, int pages, EItemSlot slot) {
		String pageurl = null;
		int catg = this.catgMapping.get(EItemType.ARMOR);
		int subcatg = this.armorSubcatgMapping.get(p);
		
		for (int page = 1; page <= pages; page++) {
			pageurl = urlPart0 + catg + urlPart1 + subcatg + "/slot/" + this.armorSlotMapping.get(slot) + urlPart2 + page;
			LinkedList<String> pageURLS = new LinkedList<String>();
			LinkedList<String> ilvl = new LinkedList<String>();
			this.getItemPageURLs(pageurl, pageURLS, ilvl);
			
			for (int i = 0; i < pageURLS.size(); i++) {
				this.parseItemPage("http://www.torhead.com/item/" + pageURLS.get(i), ilvl.get(i), slot, pageURLS.get(i));
			}

		}
		
	}
	
	private void parseItemPage(String u, String ilvl, EItemSlot slot, String torheadid) {
		ItemPageParser parser = new ItemPageParser(ilvl, slot, torheadid);
		
		try {
			URL url = new URL(u);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					url.openStream()));
			String inputLine;
			
			while ((inputLine = in.readLine()) != null) {
				parser.parse(inputLine);
			}
			
			System.out.println("Parsed " + u);
			
			this.out.write(parser.item.toString());
			
			in.close();

		} catch (MalformedURLException me) {
			System.out.println(me);

		} catch (IOException ioe) {
			System.out.println(ioe);
			try {
				Thread.sleep(10000);
				System.out.println("Retry...");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			this.parseItemPage(u, ilvl, slot, torheadid);
		}
	}

	private void getItemPageURLs(
			final String u, 
			final LinkedList<String> itemPageURLs, 
			final LinkedList<String> ilvl) {
		
		try {
			URL url = new URL(u);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					url.openStream()));
			String inputLine;
			LinkedList<String> extracted = null;
			
			while ((inputLine = in.readLine()) != null) {
				extracted = this.matches(ITEM_PATTERN, inputLine);
				for (String s : extracted) {
					itemPageURLs.add(this.extract("<a href=\"/item/", "\"></a>", s));
				}
				
				extracted = this.matches(ILVL_PATTERN, inputLine);
				for (String s : extracted) {
					//<td class="nobr">56</td><td class="nobr">50</td>
					s = this.extract("<td class=\"nobr\">", "</td>\\d+</td>", s);
					ilvl.add(s);
				}
			}
			in.close();

		} catch (MalformedURLException me) {
			System.out.println(me);

		} catch (IOException ioe) {
			System.out.println(ioe);
		}
	}

	private LinkedList<String> matches(String p, String text) {
		LinkedList<String> results = new LinkedList<String>();
		
		Pattern pattern = Pattern.compile(p);
		Matcher matcher = pattern.matcher(text);
		
		while (matcher.find()) {
			results.add(matcher.group());
		}
		
		return results;
	}

	private int getItemsOfCategory(final String u) {
		int pages = 0;
		
		try {
			URL url = new URL(u);
			BufferedReader in = new BufferedReader(new InputStreamReader(
					url.openStream()));
			String inputLine;
			String extracted;
			
			while ((inputLine = in.readLine()) != null) {
				extracted = this.match(PAGES_PATTERN, inputLine);
				if (extracted != null) {
					pages = Integer.parseInt(this.extract("</b> of <b>", "</b></span>", extracted));
				}
			}
			in.close();

		} catch (MalformedURLException me) {
			System.out.println(me);

		} catch (IOException ioe) {
			System.out.println(ioe);
		}
		
		return pages;
	}

	public static void main(final String[] args) {
		new Crawler();
	}
	
	private String match(final String p, final String text) {
		String result = null;
		
		Pattern pattern = Pattern.compile(p);
		Matcher matcher = pattern.matcher(text);
		
		while (matcher.find()) {
			result = matcher.group();
		}
		
		return result;
	}
	
	private String extract(final String start, final String end, final String text) {
		String result = null;
		
		Pattern startpattern = Pattern.compile(start);
		Pattern endpattern = Pattern.compile(end);
		
		Matcher matcher = startpattern.matcher(text);
		result = matcher.replaceAll("");
		
		matcher = endpattern.matcher(result);
		result = matcher.replaceAll("");
		
		return result;
	}
}
